package com.kbckbc.emailmemo;

import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Bundle;
import android.os.StrictMode;
import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

// * duration 기본값과 debug 모드 설정시 자동으로 낮은 값 잡히도록. 그리고 첫번째 로긴시 dialog 띄우도록 -> 완료
// * 수정시 sync 값은 자동으로 풀리나? -> 자동으로 풀리도록 해놨음!
// * 메모 저장 후 30초 뒤에 무조건 전송 시도 하고 그다음에는 delay 간격으로. -> 저장 혹은 수정일떄는 Initail delay 이용하여 쓰레드 실행되도록 정정
// * SendThemAll 만들기 -> 소스 수정했으니 검증해보면된다. -> 완료
// * unsyn 된 메모 hash 맵으로 하니 정렬이 흐트러짐 -> list 로 바꿨음. 
// TODO runOnUiThread 어떻게 쓰는건지 알아보자
public class EmailmemoActivity extends Activity {
	final static String LOG_TAG = "MAIN_ACTIVITY";
	final static boolean DEBUG = false;

	// main activity -> memo activity
	final static int ACTIVITY_CALL_TYPE_SAVE = 1;
	final static int ACTIVITY_CALL_TYPE_EDIT = 2;
	final static int ACTIVITY_CALL_TYPE_PREF = 3;

	// memo activity -> main activity
	final static int ACTIVITY_RESULT_TYPE_SAVE = 10;
	final static int ACTIVITY_RESULT_TYPE_EDIT = 11;
	final static int ACTIVITY_RESULT_TYPE_DELETE = 12;

	final static int CONTEXT_MENU_EDIT = 0;
	final static int CONTEXT_MENU_EMAIL = 1;
	final static int CONTEXT_MENU_DELETE = 2;

	final static String PREF_EMAIL_ADDR_KEY = "email";
	final static String PREF_EMAILSYNC_KEY = "syncduration";
	final static String PREF_SORT_ORDER_KEY = "sortorder";
	final static String PREF_SORT_ORDER_BY_CREATE = "1";
	final static String PREF_SORT_ORDER_BY_MODIFY = "2";

	MemoDBHelper dbHelper;

	String searchKey;
	String tagKey;

	// if you want to test normal adapter, edit visibility in main.xml layout
	ListView listviewTag;
	ArrayAdapter adapterTag;
	ArrayList<String> arrTag;

	LinearLayout layoutTag;

	// want to show custom adapter works well too
	ListView listviewMemo;
	ArrayList<Memo> arrMemo;
	MemoListAdapter adapterMyMemoList;

	ProgressDialog progress;
	Boolean testSendingMail = false;
	final static String PREF_EMAIL_ACCOUNT_KEY = "emailAccount";
	final static String PREF_EMAIL_PASSWD_KEY = "emailPasswd";

	private static String gmailId = "";
	private static String gmailEncPasswd = "";

	Button btnMailerOnOff;

	public static String getGmailId() {
		return gmailId;
	}

	public static void setGmailId(String id) {
		EmailmemoActivity.gmailId = id;
	}

	public static String getGmailEncPasswd() {
		return gmailEncPasswd;
	}

	public static void setGmailEncPasswd(String encPasswd) {
		EmailmemoActivity.gmailEncPasswd = encPasswd;
	}

	public static String getGmailPasswd() {
		return StringEncrypto.decrypt(gmailId, gmailEncPasswd);
	}

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		initThreadPolicy();
		init();
		initEvent();
		initAccount();
	}

	// Thread Policy 를 설정한다.
	// 이코드가 없으면 실제 디바이스에 올렸을때 Mail 전송하는 Thread 가 Excpetion 이 나버림
	public void initThreadPolicy() {
		if (android.os.Build.VERSION.SDK_INT > 9) {
			StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
					.permitAll().build();
			StrictMode.setThreadPolicy(policy);
		}
	}

	public void initAccount() {
		gmailId = getSharedPreferences(PrefActivity.PREF_FILE_NAME,
				MODE_PRIVATE).getString(PREF_EMAIL_ACCOUNT_KEY, "");
		gmailEncPasswd = getSharedPreferences(PrefActivity.PREF_FILE_NAME,
				MODE_PRIVATE).getString(PREF_EMAIL_PASSWD_KEY, "");

		L.v("initAccount() start.");
		L.v("id - " + gmailId);
		L.v("encPasswd - " + gmailEncPasswd);
		L.v("Passwd - " + getGmailPasswd());
		L.v("initAccount() end.");

		// 설정된 계정이 없다면 계정 설정 페이지로 이동한다.
		if ("".equals(gmailId) && "".equals(gmailEncPasswd)) {
			new AlertDialog.Builder(EmailmemoActivity.this)
					.setTitle(getString(R.string.pref_call_title))
					.setMessage(getString(R.string.pref_call_message))
					.setPositiveButton(getString(R.string.pref_call_ok_button),
							new DialogInterface.OnClickListener() {
								public void onClick(DialogInterface dialog,
										int whichButton) {
									Intent intent = new Intent(
											EmailmemoActivity.this,
											PrefActivity.class);
									startActivityForResult(
											intent,
											EmailmemoActivity.ACTIVITY_CALL_TYPE_PREF);
								}
							}).show();
		}
	}

	public void init() {
		// db
		dbHelper = new MemoDBHelper(this);

		// to show android default listview
		arrTag = new ArrayList<String>();
		adapterTag = new ArrayAdapter(this,
				android.R.layout.simple_list_item_1, arrTag);
		listviewTag = (ListView) findViewById(R.id.listTag);
		listviewTag.setAdapter(adapterTag);

		//
		arrMemo = new ArrayList<Memo>();
		adapterMyMemoList = new MemoListAdapter(this, R.layout.memolist,
				arrMemo);
		listviewMemo = (ListView) findViewById(R.id.listMemo);
		listviewMemo.setAdapter(adapterMyMemoList);

		registerForContextMenu(listviewMemo);

		searchKey = "";
		tagKey = "";

		progress = new ProgressDialog(this);
		btnMailerOnOff = (Button) findViewById(R.id.btnMailerOnOff);

		loadMemoIntoListView();

		// DEBUG 모드일때에는 10초마다 보내기
		if (DEBUG == true) {
			AutoMailer.setInitialDelay(20);
			AutoMailer.setDelay(30);
		}

		AutoMailer.setParentActivity(this);
		AutoMailer.start();
	}

	public void initEvent() {
		EditText editSearchKey = (EditText) findViewById(R.id.editSearchKey);
		// Using the TextWatcher to capture any key is pushed or not.
		// The View.onClickListener doesn't work.
		editSearchKey.addTextChangedListener(new TextWatcher() {

			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
				searchKey = s + "";

				loadMemoIntoListView();
			}

			public void afterTextChanged(Editable s) {

			}

			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}
		});

		// Message Handle - turn on search button
		ImageButton btnTurnOnSearch = (ImageButton) findViewById(R.id.btnTurnOnSearch);
		btnTurnOnSearch.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				EditText editSearchKey = (EditText) findViewById(R.id.editSearchKey);

				if (editSearchKey.getVisibility() == View.VISIBLE) {
					editSearchKey.setVisibility(View.GONE);

					searchKey = "";
					EditText editText = (EditText) findViewById(R.id.editSearchKey);
					editText.setText(searchKey);

					loadMemoIntoListView();
				} else {
					editSearchKey.setVisibility(View.VISIBLE);

					EditText editText = (EditText) findViewById(R.id.editSearchKey);
					editText.requestFocus();
				}
			}
		});

		// Message Handle - create text file button
		ImageButton btnNew = (ImageButton) findViewById(R.id.btnNew);
		btnNew.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				callMemoActivity();
			}
		});

		// Message Handle - create draw file button
		Button btnDraw = (Button) findViewById(R.id.btnPrefClean);
		btnDraw.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				getSharedPreferences(PrefActivity.PREF_FILE_NAME, MODE_PRIVATE)
						.edit().putString(PREF_EMAIL_ACCOUNT_KEY, "").commit();

				getSharedPreferences(PrefActivity.PREF_FILE_NAME, MODE_PRIVATE)
						.edit().putString(PREF_EMAIL_PASSWD_KEY, "").commit();

				EmailmemoActivity.setGmailId("");
				EmailmemoActivity.setGmailEncPasswd("");
			}
		});

		// Message Handle - create draw file button
		Button btnAutoMailerOnOff = (Button) findViewById(R.id.btnMailerOnOff);
		btnAutoMailerOnOff.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				if (AutoMailer.isWorking()) {
					AutoMailer.stop();
					btnMailerOnOff.setText("Stopped");
				} else {
					AutoMailer.reset();
					btnMailerOnOff.setText("working");
				}
			}
		});

		listviewTag.setOnItemClickListener(new OnItemClickListener() {

			public void onItemClick(AdapterView arg0, View view, int position,
					long id) {
				tagKey = arrTag.get(position);
				if (tagKey.equals("All")) {
					tagKey = "";
				}

				loadMemoIntoListView();
			}
		});

		listviewMemo.setOnItemClickListener(new OnItemClickListener() {

			public void onItemClick(AdapterView arg0, View view, int position,
					long id) {
				L.v(this, "listviewMemo.setOnItemClickListener() : position - "
						+ position);

				callMemoActivity(position);
			}
		});

		listviewMemo.setOnItemLongClickListener(new OnItemLongClickListener() {

			public boolean onItemLongClick(AdapterView arg0, View view,
					final int position, long id) {
				// String[] strLongClickItem = { "Edit", "Sharing", "Delete" };
				// new AlertDialog.Builder(EmailmemoActivity.this)
				// .setTitle("Select one")
				// .setItems(strLongClickItem,
				// new DialogInterface.OnClickListener() {
				//
				// public void onClick(DialogInterface dialog,
				// int which) {
				// switch (which) {
				// case CONTEXT_MENU_EDIT:
				// callMemoActivity(position);
				// break;
				//
				// case CONTEXT_MENU_EMAIL:
				// shareAMemo(position);
				// break;
				//
				// case CONTEXT_MENU_DELETE:
				// callDeleteMemoDialog(position);
				// break;
				// }
				// }
				// }).setNegativeButton("Cancel", null).show();

				return true;
			}
		});
	}

	View insertTagView(String tag) {
		LinearLayout tagLayout = new LinearLayout(getApplicationContext());

		TextView tagView = new TextView(getApplicationContext());
		tagView.setPadding(20, 5, 20, 5);
		tagView.setTextSize(18);
		tagView.setText(tag);

		tagView.setOnClickListener(new OnClickListener() {
			public void onClick(View arg0) {
				tagKey = (String) ((TextView) arg0).getText();

				if (tagKey.equals("Pick tag -")) {
					return;
				}

				if (tagKey.equals("All")) {
					tagKey = "";
				}

				loadMemoIntoListView();
			}
		});

		tagLayout.addView(tagView);

		return tagLayout;
	}

	public int getMemoCount() {
		return arrMemo.size();
	}

	public void loadMemoIntoListView() {
		L.v("loadMemoIntoListView start");

		// clear before loading
		arrTag.clear();
		arrMemo.clear();

		// db..
		SQLiteDatabase db;
		db = dbHelper.getReadableDatabase();
		Cursor cursor;

		// load memo list
		String sqlLoadMemoList;
		if (getPrefSortOrder().equals(PREF_SORT_ORDER_BY_CREATE)) {
			sqlLoadMemoList = String.format(Query.selectMemoOrderByCreation,
					searchKey, tagKey);
		} else {
			sqlLoadMemoList = String.format(
					Query.selectMemoOrderByModification, searchKey, tagKey);
		}

		L.v(this, sqlLoadMemoList);

		cursor = db.rawQuery(sqlLoadMemoList, null);
		while (cursor.moveToNext()) {
			Memo currMemo = new Memo(false, cursor.getInt(0),
					cursor.getString(1), cursor.getString(2),
					cursor.getString(3), cursor.getString(4),
					cursor.getString(5), cursor.getString(6));

			arrMemo.add(currMemo);
		}

		// load tag list
		String sqlLoadTagList = Query.selectTagOrderByCharacter;

		arrTag.add("Pick tag -");
		arrTag.add("All");
		cursor = db.rawQuery(sqlLoadTagList, null);
		while (cursor.moveToNext()) {
			arrTag.add(cursor.getString(0));
		}

		L.v(this, sqlLoadTagList);

		cursor.close();
		db.close();

		// load tags into tag layout
		layoutTag = (LinearLayout) findViewById(R.id.tagLayout);
		layoutTag.removeAllViews();
		for (int i = 0; i < arrTag.size(); i++) {
			layoutTag.addView(insertTagView(arrTag.get(i)));
		}

		// notify changes
		try {
			adapterMyMemoList.notifyDataSetChanged();
			adapterTag.notifyDataSetChanged();
		} catch (Exception e) {
			e.printStackTrace();
		}

		if (arrMemo.size() == 0) {
			Toast.makeText(EmailmemoActivity.this,
					getString(R.string.toast_no_memo), Toast.LENGTH_SHORT)
					.show();
		}
	}

	public void callMemoActivity() {
		Intent intent = new Intent(EmailmemoActivity.this, MemoActivity.class);
		startActivityForResult(intent, ACTIVITY_CALL_TYPE_SAVE);
	}

	public void callMemoActivity(int pos) {
		int memo_id = arrMemo.get(pos)._id;
		String memo_content = arrMemo.get(pos).content;
		String memo_tag = arrMemo.get(pos).tag;
		String memo_image_path = arrMemo.get(pos).getConcatenatedImagePath();

		Intent intent = new Intent(EmailmemoActivity.this, MemoActivity.class);
		intent.putExtra("memo_pos", pos);
		intent.putExtra("memo_id", memo_id);
		intent.putExtra("memo_content", memo_content);
		intent.putExtra("memo_tag", memo_tag);
		intent.putExtra("memo_image_path", memo_image_path);

		L.v(this, "callMemoActivity() --");
		L.v(this, "memo_pos " + pos);
		L.v(this, "memo_id " + memo_id);
		L.v(this, "memo_content " + memo_content);
		L.v(this, "memo_tag " + memo_tag);
		L.v(this, "memo_image_path " + memo_image_path);
		L.v(this, "callMemoActivity() --");

		startActivityForResult(intent, ACTIVITY_CALL_TYPE_EDIT);
	}

	public String getPrefEmailAddr() {
		return PreferenceManager.getDefaultSharedPreferences(this).getString(
				PREF_EMAIL_ADDR_KEY, "");
	}

	public int getPrefEmailsyncTimeDuration() {
		return PreferenceManager.getDefaultSharedPreferences(this).getInt(
				PREF_EMAILSYNC_KEY, 600);
	}

	public String getPrefSortOrder() {
		return PreferenceManager.getDefaultSharedPreferences(this).getString(
				PREF_SORT_ORDER_KEY, PREF_SORT_ORDER_BY_CREATE);
	}

	public String getEmailSubject() {
		return "[Emailmemo] - "
				+ DateFormat.getDateTimeInstance().format(new Date());
	}

	public String getEmailContent(int selectedItem) {
		ArrayList<Integer> param = new ArrayList<Integer>();
		param.add(selectedItem);
		return getEmailContent(param);
	}

	public String getEmailContent(ArrayList<Integer> selectedItems) {
		String emailContent = "";
		int selectedPos;
		for (int i = 0; i < selectedItems.size(); i++) {
			selectedPos = selectedItems.get(i);

			if (getPrefSortOrder().equals(PREF_SORT_ORDER_BY_CREATE)) {
				emailContent += getString(R.string.share_email_sort_order1)
						+ " " + arrMemo.get(selectedPos).create_dttm + "\n"
						+ getString(R.string.share_email_content) + "\n"
						+ arrMemo.get(selectedPos).content;
			} else {
				emailContent += getString(R.string.share_email_sort_order1)
						+ " " + arrMemo.get(selectedPos).modf_dttm + "\n"
						+ getString(R.string.share_email_content) + "\n"
						+ arrMemo.get(selectedPos).content;
			}

			if (i != selectedItems.size() - 1) {
				emailContent += "\n\n";
			}
		}

		return emailContent;
	}

	public ArrayList<String> getEmailAttachments(int selectedPos) {
		return arrMemo.get(selectedPos).getImagePathArrayList();
	}

	// Sharing a memo. In this case texts and images can be put together in a
	// mail
	public void shareAMemo(int itemPos) {
		String emailAddr = "";
		String emailSubject = "";
		String emailContent = "";
		ArrayList<String> emailAttachments = new ArrayList<String>();

		emailAddr = getPrefEmailAddr();

		L.v(this, "shareMemos - emailAddr " + emailAddr);

		// A email addr isn't specified, then call the pref Activity.
		if (emailAddr.length() == 0 || emailAddr.equals("")) {
			callPrefActivity();
		} else {
			emailSubject = getEmailSubject();
			emailContent = getEmailContent(itemPos);
			emailAttachments = getEmailAttachments(itemPos);

			callSharingActivity(emailAddr, emailSubject, emailContent,
					emailAttachments);
		}
	}

	public void callSharingActivity(String addr, String subject,
			String content, ArrayList<String> arrImagePath) {
		Intent i;
		ArrayList<Uri> uris = new ArrayList<Uri>();

		if (arrImagePath == null) {
			i = new Intent(Intent.ACTION_SEND);
			i.setType("text/plain");
			i.putExtra(Intent.EXTRA_EMAIL, new String[] { addr });
			i.putExtra(Intent.EXTRA_SUBJECT, subject);
			i.putExtra(Intent.EXTRA_TEXT, content);
		} else {
			for (String file : arrImagePath) {
				File fileIn = new File(file);
				Uri u = Uri.fromFile(fileIn);
				uris.add(u);
			}

			i = new Intent(Intent.ACTION_SEND_MULTIPLE);
			i.setType("image/*");
			i.putExtra(Intent.EXTRA_EMAIL, new String[] { addr });
			i.putExtra(Intent.EXTRA_SUBJECT, subject);
			i.putExtra(Intent.EXTRA_TEXT, content);
			i.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
		}

		try {
			startActivity(Intent.createChooser(i,
					getString(R.string.share_call_title)));
		} catch (android.content.ActivityNotFoundException ex) {
			Toast.makeText(EmailmemoActivity.this,
					getString(R.string.toast_no_email_client),
					Toast.LENGTH_SHORT).show();
		}
	}

	public void callPrefActivity() {
		new AlertDialog.Builder(EmailmemoActivity.this)
				.setTitle(getString(R.string.pref_call_title))
				.setMessage(getString(R.string.pref_call_message))
				.setPositiveButton(getString(R.string.pref_call_ok_button),
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog,
									int whichButton) {
								Intent intent = new Intent(
										EmailmemoActivity.this,
										PrefActivity.class);
								startActivityForResult(
										intent,
										EmailmemoActivity.ACTIVITY_CALL_TYPE_PREF);
							}
						}).show();
	}

	public void deleteMemoWithPos(int pos) {
		if (getMemoCount() != 0) {
			deleteMemoWithId(arrMemo.get(pos)._id);
		}
	}

	public void deleteMemoWithMultiplePos(ArrayList<Integer> items) {
		String deleteIds = "";
		for (int i = 0; i < items.size(); i++) {
			deleteIds += arrMemo.get(items.get(i))._id;
			if (i != items.size() - 1) {
				deleteIds += ",";
			}
		}

		deleteMemoWithMultipleId(deleteIds);
	}

	public void deleteMemoWithId(int id) {
		deleteMemoWithMultipleId(id + "");
	}

	public void deleteMemoWithMultipleId(String memoId) {
		String sql = String.format(Query.deleteMemo, memoId);

		SQLiteDatabase db;
		db = dbHelper.getWritableDatabase();
		db.execSQL(sql);
		db.close();
	}

	public void callDeleteMemoDialog(int selectedItem) {
		ArrayList<Integer> arrTemp = new ArrayList<Integer>();
		arrTemp.add(selectedItem);
		callDeleteMemoDialog(arrTemp);
	}

	public void callDeleteMemoDialog(final ArrayList<Integer> selectedItems) {
		new AlertDialog.Builder(EmailmemoActivity.this)
				.setMessage(getString(R.string.memo_delete_message))
				.setTitle(getString(R.string.app_name))
				.setPositiveButton(
						getString(R.string.memo_delete_positive_button),
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog,
									int whichButton) {

								deleteMemoWithMultiplePos(selectedItems);

								loadMemoIntoListView();
							}
						})
				.setNegativeButton(
						getString(R.string.memo_delete_negative_button),
						new DialogInterface.OnClickListener() {

							public void onClick(DialogInterface dialog,
									int which) {
							}
						}).show();
	}

	public void insertMemo(String content, String time, String tag,
			String image_path, String sync) {
		String sql = String.format(Query.insertMemo, content, time, time, tag,
				image_path, sync);

		L.v(this, "insertMemo() --");
		L.v(this, sql);
		L.v(this, "insertMemo() --");

		SQLiteDatabase db;
		db = dbHelper.getWritableDatabase();
		db.execSQL(sql);
		db.close();

	}

	public void updateMemo(int id, String time, String content, String tag,
			String imagePath, String sync) {
		String sql = String.format(Query.updateMemo, content, tag, imagePath,
				time, sync, id);

		L.v(this, "updateMemo() --");
		L.v(this, sql);
		L.v(this, "updateMemo() --");

		SQLiteDatabase db;
		db = dbHelper.getWritableDatabase();
		db.execSQL(sql);
		db.close();
	}

	// memo 중에 메일로 보낸 것에 대해서 완료 값으로 update 한다.
	public void updateMemoSyncComplete(ArrayList<Integer> arrUnsyncMemoId) {
		SQLiteDatabase db = null;

		try {
			db = dbHelper.getWritableDatabase();
		} catch (Exception e) {
			e.printStackTrace();
		}

		if (db == null) {
			return;
		}

		// sync 값을 update 할 때 sql in 구절로 할 것인데
		// in 구절 갯수가 1000 개 정도인걸로 알고 있음. 혹시 넘어갈까봐 ㅋㅋㅋ
		int divide = 100;
		String concatenatedId = "";

		for (int i = 0; i < arrUnsyncMemoId.size(); i++) {
			concatenatedId += arrUnsyncMemoId.get(i) + ",";

			if (i != 0 && i % divide == 0) {
				// delete last comma
				concatenatedId = concatenatedId.substring(0,
						concatenatedId.length() - 1);

				String sql = String.format(Query.updateMemoSyncComplete, "y",
						concatenatedId);

				L.v(this, sql);

				db.execSQL(sql);

				concatenatedId = "";
			}

		}

		if (concatenatedId != "") {
			// delete last comma
			concatenatedId = concatenatedId.substring(0,
					concatenatedId.length() - 1);

			String sql = String.format(Query.updateMemoSyncComplete, "y",
					concatenatedId);

			L.v(this, sql);

			db.execSQL(sql);
		}

		db.close();

		// updateMemoSyncComplete 함수는 다른 Thread 에서 콜이 되는 함수인데
		// 다른 activity 에 있는 listview 를 update 하려고 하면 위반이다.
		// 그래서 여기서 listview 에다가 이벤트를 post 하는 것임.
		listviewMemo.post(new Runnable() {
			public void run() {
				try {
					loadMemoIntoListView();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	public void updateAllMemoUnsync() {
		String sql = String.format(Query.updateAllMemoUnSync);

		L.v(this, "updateAllMemoUnsync() --");
		L.v(this, sql);
		L.v(this, "updateAllMemoUnsync() --");

		SQLiteDatabase db;
		db = dbHelper.getWritableDatabase();
		db.execSQL(sql);
		db.close();
	}

	// For option menu
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.layout.optionmenu, menu);

		return true;
	}

	// For option menu
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.about:
			new AlertDialog.Builder(EmailmemoActivity.this)
					.setTitle(getString(R.string.app_name))
					.setMessage(
							getString(R.string.option_menu_item_about_message))
					.setIcon(R.drawable.ic_launcher)
					.setPositiveButton("Ok", null).show();
			return true;

		case R.id.pref:
			L.v(this, "pref");

			Intent intent = new Intent(EmailmemoActivity.this,
					PrefActivity.class);
			startActivityForResult(intent, ACTIVITY_CALL_TYPE_PREF);

			return true;

		case R.id.selectall:
			adapterMyMemoList.setCheckAll();
			return true;

			// 다중 선택시 문제가 될 수 있기 때문에 다중선택에서는 삭제만 가능하도록 한다.
			/*
			 * case R.id.send: if (adapterMyMemoList.getSelectedItemIds().size()
			 * == 0) { Toast.makeText(EmailmemoActivity.this,
			 * "Check items first.", Toast.LENGTH_SHORT).show(); } else if
			 * (adapterMyMemoList.getSelectedItemIds().size() == 1) {
			 * shareAMemo(adapterMyMemoList.getSelectedItemIds().get(0)); } else
			 * { new AlertDialog.Builder(EmailmemoActivity.this) .setMessage(
			 * "If you made a multiple select then you can send only contents of memos.\nIf you want to send images of the memos, then choose a memo and then share a memo."
			 * ) .setTitle("Email Memo") .setPositiveButton("Yes", new
			 * DialogInterface.OnClickListener() { public void
			 * onClick(DialogInterface dialog, int whichButton) {
			 * 
			 * shareMemos(adapterMyMemoList .getSelectedItemIds()); } })
			 * .setNegativeButton("No", new DialogInterface.OnClickListener() {
			 * 
			 * public void onClick(DialogInterface dialog, int which) { }
			 * }).show();
			 * 
			 * }
			 * 
			 * return true;
			 */
		case R.id.delete:
			if (adapterMyMemoList.getSelectedItemIds().size() == 0) {
				Toast.makeText(EmailmemoActivity.this,
						getString(R.string.toast_check_item_first),
						Toast.LENGTH_SHORT).show();
			} else {
				callDeleteMemoDialog(adapterMyMemoList.getSelectedItemIds());
			}

			return true;

		case R.id.sendthemall:
			if ("".equals(getGmailId())) {
				Toast.makeText(EmailmemoActivity.this,
						getString(R.string.toast_check_item_first),
						Toast.LENGTH_SHORT).show();
			} else {
				updateAllMemoUnsync();
				AutoMailer.resetWithoutInitialDelay();
			}

			return true;
		}

		return false;
	}

	// function will be called when a Activity which is created by
	// startActivityForResult() is closed.
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		switch (requestCode) {
		case ACTIVITY_CALL_TYPE_SAVE:
		case ACTIVITY_CALL_TYPE_EDIT:
			if (resultCode == RESULT_OK) {
				// MemoActivity -> MainActivity param.
				int memo_result_type;
				int memo_pos;
				int memo_id;
				String memo_content;
				String memo_tag;
				String memo_changed;
				String memo_image_path;
				String memo_sync;

				memo_result_type = data.getIntExtra("memo_result_type", 0);
				memo_pos = data.getIntExtra("memo_pos", -1);
				memo_id = data.getIntExtra("memo_id", -1);
				memo_changed = data.getStringExtra("memo_changed");
				memo_content = data.getStringExtra("memo_content");
				memo_tag = data.getStringExtra("memo_tag");
				memo_image_path = data.getStringExtra("memo_image_path");
				memo_sync = "";

				// check time
				SimpleDateFormat format = new SimpleDateFormat(
						"yyyy.MM.dd HH:mm:ss");
				String memo_time = format.format(new Date());

				L.v(this, "onActivityResult callback() --");
				L.v(this, "memo_result_type " + memo_result_type);
				L.v(this, "memo_pos " + memo_pos);
				L.v(this, "memo_id " + memo_id);
				L.v(this, "memo_changed " + memo_changed);
				L.v(this, "memo_content " + memo_content);
				L.v(this, "memo_tag " + memo_tag);
				L.v(this, "memo_image_path " + memo_image_path);
				L.v(this, "onActivityResult callback() --");

				if (memo_result_type == ACTIVITY_RESULT_TYPE_DELETE) {
					deleteMemoWithId(memo_id);
				} else if (memo_result_type == ACTIVITY_RESULT_TYPE_SAVE
						&& "true".equals(memo_changed)) {
					insertMemo(memo_content, memo_time, memo_tag,
							memo_image_path, memo_sync);

					// after insert new memo, memo position is always 0.
					memo_pos = 0;
				} else if (memo_result_type == ACTIVITY_RESULT_TYPE_EDIT
						&& "true".equals(memo_changed)) {
					updateMemo(memo_id, memo_time, memo_content, memo_tag,
							memo_image_path, memo_sync);
				}
				loadMemoIntoListView();

				AutoMailer.reset();
			}

			break;
		case ACTIVITY_CALL_TYPE_PREF:
			loadMemoIntoListView();
			break;
		}
	}

	public ArrayList<Memo> getUnsyncMemoList() {
		ArrayList<Memo> listUnsyncMemo = new ArrayList<Memo>();
		// db..
		SQLiteDatabase db;
		db = dbHelper.getReadableDatabase();
		Cursor cursor;

		int resultCnt = 0;
		L.v(this, "getUnsyncMemoList start.\n\t"
				+ Query.selectUnsyncMemoOrderByCreation);

		cursor = db.rawQuery(Query.selectUnsyncMemoOrderByCreation, null);
		while (cursor.moveToNext()) {
			Memo currMemo = new Memo(false, cursor.getInt(0),
					cursor.getString(1), cursor.getString(2),
					cursor.getString(3), cursor.getString(4),
					cursor.getString(5), cursor.getString(6));

			listUnsyncMemo.add(currMemo);

			resultCnt++;
		}

		cursor.close();
		db.close();

		if (resultCnt == 0) {
			L.v(this, "\t" + "There's no unsync memo.");
		}
		L.v(this, "getUnsyncMemoList end.");

		return listUnsyncMemo;
	}
	
}